package com.dhecp.framework.shiro.realm;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.dhecp.common.exception.user.CaptchaException;
import com.dhecp.common.exception.user.RoleBlockedException;
import com.dhecp.common.exception.user.UserBlockedException;
import com.dhecp.common.exception.user.UserIdLengthException;
import com.dhecp.common.exception.user.UserNotExistsException;
import com.dhecp.common.exception.user.UserPasswordLengthException;
import com.dhecp.common.exception.user.UserPasswordNotMatchException;
import com.dhecp.common.exception.user.UserPasswordRetryLimitExceedException;
import com.dhecp.common.utils.StringUtils;
import com.dhecp.framework.shiro.service.SysLoginService;
import com.dhecp.framework.util.ShiroUtils;
import com.dhecp.project.system.domain.SysUserInfo;
import com.dhecp.project.system.service.SysRoleInfoService;
import com.dhecp.project.system.service.SysUserAndRoleJurisdictionService;

/**
 * 自定义Realm 处理登录 权限
 * 
 * @author ruoyi
 */
public class UserRealm extends AuthorizingRealm
{
    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private SysUserAndRoleJurisdictionService sysUserAndRoleJurisdictionService;

    @Autowired
    private SysRoleInfoService sysRoleInfoService;

    @Autowired
    private SysLoginService loginService;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
    {        
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        
        //当前登录用户编号
        String loginUser = ShiroUtils.getUserId();
        //委托（被代理）用户编号，非代理情况下为当前登录用户编号
        String mandator = ShiroUtils.getMandatorId();
        
        //委托（被代理）用户信息，非代理情况下为当前登录用户信息
        SysUserInfo mandatorInfo = ShiroUtils.getMandatorUser();
      
        // 角色列表
        Set<String> roles = new HashSet<String>();
        // 功能列表
        Set<String> menus = new HashSet<String>();
                
        // 角色加入AuthorizationInfo认证对象
        roles = sysRoleInfoService.queryRoleInfoListByUserIdToString(mandator);
        info.setRoles(roles);
        // 6级开始添加 系统管理员 角色
        if (StringUtils.isNotNull(mandatorInfo) && mandatorInfo.getUserLevel() > 5){
        	info.addRole("系统管理员");
        }
        
        // shiro功能权限标识加入AuthorizationInfo认证对象
        if (StringUtils.isNotNull(mandatorInfo) && mandatorInfo.getUserLevel() == 10){
        	info.addStringPermission("*:*:*");
        }else{
        	Map<String,Object> params = new HashMap<String,Object> ();
        	params.put("userId", loginUser);
        	params.put("mandator", mandator);
            menus = sysUserAndRoleJurisdictionService.queryJurisdictionForShiroToString(params);
            info.setStringPermissions(menus);
            info.addStringPermission("system:menu:list"); //登录用户都需要有菜单显示权限
            info.addStringPermission("system:user:view"); //登录用户都需要查看用户信息的权限
            info.addStringPermission("system:user:list"); //登录用户都需要查看用户信息的权限
            info.addStringPermission("system:depot:list"); //登录用户都需要查看仓库信息的权限
        }
        
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
    {
        CustomUsernamePasswordToken upToken = (CustomUsernamePasswordToken) token;
        String username = upToken.getUsername();
        boolean freePwd = upToken.getFreePwd();
        String userAgent = upToken.getHost();
        String password = "";
        if (upToken.getPassword() != null)
        {
            password = new String(upToken.getPassword());
        }

        SysUserInfo user = null;
        try
        {
            user = loginService.login(username, password, userAgent,freePwd);
        }
        catch (CaptchaException e)
        {
            throw new AuthenticationException(e.getMessage(), e);
        }
        catch (UserNotExistsException e)
        {
            throw new UnknownAccountException(e.getMessage(), e);
        }
        catch (UserIdLengthException e)
        {
            throw new IncorrectCredentialsException(e.getMessage(), e);
//            throw new IncorrectCredentialsException(MessageUtils.message("user.userId.length.error",UserConstants.USERNAME_MIN_LENGTH,UserConstants.USERNAME_MAX_LENGTH), e);
        }
        catch (UserPasswordLengthException e)
        {
            throw new IncorrectCredentialsException(e.getMessage(), e);
//            throw new IncorrectCredentialsException(MessageUtils.message("user.password.length.error",UserConstants.PASSWORD_MIN_LENGTH,UserConstants.PASSWORD_MAX_LENGTH), e);
        }
        catch (UserPasswordNotMatchException e)
        {
            throw new IncorrectCredentialsException(e.getMessage(), e);
        }
        catch (UserPasswordRetryLimitExceedException e)
        {
            throw new ExcessiveAttemptsException(e.getMessage(), e);
        }
        catch (UserBlockedException e)
        {
            throw new LockedAccountException(e.getMessage(), e);
        }
        catch (RoleBlockedException e)
        {
            throw new LockedAccountException(e.getMessage(), e);
        }
        catch (Exception e)
        {
            log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
            throw new AuthenticationException(e.getMessage(), e);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo()
    {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}
